#ifndef UNDER_CE

#include "windows.h"
#include <stdio.h>      
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
//#include "util.h"
#include "filebmp.h"
#include "tchar.h"

#define MAX_LINEWIDTH		4096

#pragma pack(1)
typedef struct
{
	BYTE Id[2];
	DWORD FileSize;
	WORD reserved[2];
	DWORD HeaderSize;
	DWORD InfoSize;
	DWORD Width;
	DWORD Depth;
	WORD biPlanes;
	WORD Bits;
	DWORD biCompression;
	DWORD biSizeImage;
	DWORD biXPelsPerMeter;
	DWORD biYPelsPerMeter;
	DWORD biClrUsed;
	DWORD biClrImportant;
} BMPHEAD;

typedef struct 
{
	BYTE Id[2];
	DWORD FileSize;
	WORD reserved[2];
	DWORD HeaderSize;
	DWORD InfoSize;
	WORD Width;
	WORD Depth;
	WORD biPlanes;
	WORD Bits;
} BMPCOREHEAD;

BOOL BmpGetBuffer(LPFILEBITMAP);
BOOL BmpCreatePalette(LPFILEBITMAP lp);

HFILEBITMAP WINAPI BmpCreate(LPTSTR lpszPath)
{
	FILE *fp;
	BMPHEAD bmp;
	BMPCOREHEAD *bmc;
//	char *linebuffer;
	char linebuffer[MAX_LINEWIDTH];
	int i, n, j, bytes;
//	HGLOBAL hmem;
	TCHAR path[256];
	HFILEBITMAP hf;
	LPFILEBITMAP lp;
#ifdef _WIN32
	char *pr, *pl, *p;
#else
	char huge *pr, huge *pl, huge *p;
#endif
	
	hf = GlobalAlloc(GHND, sizeof(FILEBITMAP));
	if (hf == NULL)
		return NULL;
  lp = (LPFILEBITMAP)GlobalLock(hf);
  if (lp == NULL)
  {
  	GlobalFree(hf);
  	return NULL;
  }

	lstrcpy((LPTSTR)path, lpszPath);
	if ((fp = fopen(path, "rb")) == NULL)
		return NULL;
                   
	lstrcpy(lp->szBitmap, (LPSTR)path);
		
//	lp->fi.PutLine = BmpPutLine;
//	if (ghImage != NULL)
//		GlobalFree(ghImage);

	fseek(fp, 0L, SEEK_END);
	lp->fi.FileSize = ftell(fp);
	fseek(fp, 0L, SEEK_SET);
	
	MEMCPY(lp->fi.Palette, (LPSTR)"\000\000\000\377\377\377", 6);
	if (fread((void *)&bmp, 1, sizeof(BMPHEAD), fp) == sizeof(BMPHEAD))
	{
		if (strncmp(bmp.Id, "BM", 2) == 0)
		{
			if (bmp.InfoSize == 12L)
			{
				bmc = (BMPCOREHEAD *)&bmp;
				lp->fi.Width = bmc->Width;
				lp->fi.Depth = bmc->Depth;
				lp->fi.Bits = bmc->Bits;
				fseek(fp, (long)sizeof(BMPCOREHEAD), SEEK_SET);
			}
			else
			{
				lp->fi.Width = (int)bmp.Width;
				lp->fi.Depth = (int)bmp.Depth;
				lp->fi.Bits = (int)bmp.Bits;
			}

			lp->fi.BackGround = 0;
			
			lp->fi.ImageSize = (long)pixels2bytes(lp->fi.Width) * (long)lp->fi.Bits * (long)lp->fi.Depth;				
      if ((lp->fi.Bits > 1) && (lp->fi.Bits <= 8))
      {
      	n = 1<<lp->fi.Bits;
      	for (i = 0; i < n; ++i)
      	{
      		lp->fi.Palette[(i * RGB_SIZE) + RGB_BLUE] = fgetc(fp);
      		lp->fi.Palette[(i * RGB_SIZE) + RGB_GREEN] = fgetc(fp);
      		lp->fi.Palette[(i * RGB_SIZE) + RGB_RED] = fgetc(fp);
      		if (bmp.InfoSize != 12L)
      			fgetc(fp);
      	}
      }
      else
      {
      	if (lp->fi.Bits == 24)
      		for (i = 0; i < 256; ++i)

				MEMSET(lp->fi.Palette + (i * RGB_SIZE), i, RGB_SIZE);
      }

			if (lp->fi.Bits == 1)
				bytes = pixels2bytes(lp->fi.Width);
			else if (lp->fi.Bits == 4)
				bytes = pixels2bytes(lp->fi.Width) << 2;
			else if (lp->fi.Bits == 8)
				bytes = lp->fi.Width;
			else if (lp->fi.Bits == 24)
				bytes = lp->fi.Width * 3;

			if (bytes & 0x0003)
			{
				bytes |= 0x0003;
				++bytes;
			}			
			if (!BmpGetBuffer(lp))
			{
				GlobalUnlock(hf);
				GlobalFree(hf);
				fclose(fp);
				return NULL;
			}

			if (!BmpCreatePalette(lp))
			{
				GlobalFree(lp->hImage);
				GlobalUnlock(hf);
				GlobalFree(hf);
				fclose(fp);
				return NULL;
			}

			fseek(fp, bmp.HeaderSize, SEEK_SET);
			
			for (i = 0; i < (int)lp->fi.Depth; ++i)
			{
				if ((int)fread(linebuffer, 1, bytes, fp) != bytes)
				{
					GlobalFree(lp->hImage);
					DeleteObject(lp->hPalette);
					GlobalUnlock(hf);
					GlobalFree(hf);
					fclose(fp);
					return NULL;
				}
#ifdef _WIN32
				pl = (char *)GlobalLock(lp->hImage);
#else
				pl = (char huge*)GlobalLock(lp->hImage);
#endif
				if (pl == NULL)
				{
					GlobalFree(lp->hImage);
					DeleteObject(lp->hPalette);
					GlobalUnlock(hf);
					GlobalFree(hf);
					fclose(fp);
					return NULL;
				}
				pr = pl + ((long)lp->nLineWidth * i);
#ifdef _WIN32
				p = (char *)linebuffer;
#else
				p = (char huge*)linebuffer;
#endif
				for (j = 0; j < lp->nLineWidth; j++)
				{
					*pr++ = *p++;	
				}
			}

			fclose(fp);
			GlobalUnlock(hf);
			return (HFILEBITMAP)hf;
		}
		else
		{
			fclose(fp);
			GlobalUnlock(hf);
			GlobalFree(hf);
			return NULL;
		}
	}
	else
	{
		fclose(fp);
		GlobalUnlock(hf);
		GlobalFree(hf);
		return NULL;
	}			
	return NULL;
}

BOOL BmpCreatePalette(LPFILEBITMAP lp)
{
	HGLOBAL hl;
	LOGPALETTE *pLogPal;
	SHORT n;
	int i, j, r = FALSE;
	
	n = 1 << lp->fi.Bits;
	j = __max(n,256);
	
	hl = GlobalAlloc(LHND, sizeof(LOGPALETTE) + (j * sizeof(PALETTEENTRY)));
	if (hl == NULL)
		return FALSE;
	pLogPal = (LOGPALETTE *)GlobalLock(hl);
	if (pLogPal == NULL)
	{
		GlobalFree(hl);
		return FALSE;
	}	
	pLogPal->palVersion = 0x0300;
	pLogPal->palNumEntries = j;
		
	for (i = 0; i < j; i++)
	{
		pLogPal->palPalEntry[i].peRed = lp->fi.Palette[i * RGB_SIZE + RGB_RED];
		pLogPal->palPalEntry[i].peGreen = lp->fi.Palette[i * RGB_SIZE + RGB_GREEN];
		pLogPal->palPalEntry[i].peBlue = lp->fi.Palette[i * RGB_SIZE + RGB_BLUE];
		pLogPal->palPalEntry[i].peFlags = 0;
	}                                      
		
	lp->hPalette = CreatePalette(pLogPal);
	GlobalUnlock(hl);
	GlobalFree(hl);
	return TRUE;
}
 
int BmpGetBuffer(LPFILEBITMAP lp)
{
	unsigned long size;
	
	if (lp->fi.Bits == 1)
	{
		lp->nImageBits = 1;
		lp->nLineWidth = pixels2bytes(lp->fi.Width);
		if (lp->nLineWidth & 0x003)
			lp->nLineWidth = (lp->nLineWidth | 3) + 1;
		size = (long)lp->nLineWidth * (long)(lp->fi.Depth + 1);
	}
	else if ((lp->fi.Bits > 1) && (lp->fi.Bits <= 4))
	{
		lp->nImageBits = 4;
		lp->nLineWidth = pixels2bytes(lp->fi.Width) << 2;
		if (lp->nLineWidth & 0x003)
			lp->nLineWidth = (lp->nLineWidth | 3) + 1;
		size = (long)lp->nLineWidth * (long)(lp->fi.Depth + 1);
	}
	else if ((lp->fi.Bits > 4) && (lp->fi.Bits <= 8))
	{
		lp->nImageBits = 8;
		lp->nLineWidth = lp->fi.Width;
		if (lp->nLineWidth & 0x003)
			lp->nLineWidth = (lp->nLineWidth | 3) + 1;
		size = (long)lp->nLineWidth * (long)(lp->fi.Depth + 1);
	}
	else 
	{
		lp->nImageBits = 24;
		lp->nLineWidth = lp->fi.Width * RGB_SIZE;
		if (lp->nLineWidth & 0x003)
			lp->nLineWidth = (lp->nLineWidth | 3) + 1;
		size = (long)lp->nLineWidth * (long)(lp->fi.Depth + 1);
	}                                    
	
	lp->nPageDepth = lp->fi.Depth;
	
	if ((lp->hImage = GlobalAlloc(GHND, size)) == NULL)
  {
		return FALSE;
	}
	else
		return TRUE;
}
 
BOOL WINAPI BmpPaint(HFILEBITMAP hf, HDC hDC, RECT rc, BOOL bTile, HBRUSH hbr)
{
	LPFILEBITMAP lp;
	LPBITMAPINFO pDibInfo;           
	HGLOBAL hDibInfo;
	int i, j;
	SHORT n;
	HBITMAP hbmp;
	HPALETTE hpalOld;
	LPSTR p;         
	HDC hdcMem;                                                    
	HBITMAP hbmpOld;                                         
	int x,y;

	if (hf == NULL)
	{
		FillRect(hDC, &rc, hbr);
		return TRUE;
	}

	lp = (LPFILEBITMAP)GlobalLock(hf);
	if (lp == NULL)
	{
		FillRect(hDC, &rc, hbr);
		return TRUE;
	}
	if (lp->hImage == NULL)
	{
		FillRect(hDC, &rc, hbr);
		return TRUE;
	}
	if ((p = GlobalLock(lp->hImage)) == NULL)
		return FALSE;
	
	n = 1 << lp->nImageBits;
	j = __max(n,256);

	hpalOld = SelectPalette(hDC, lp->hPalette, 0);
	RealizePalette(hDC);

	hDibInfo = GlobalAlloc(GPTR, sizeof(BITMAPINFOHEADER) + j * sizeof(RGBQUAD));
	if (hDibInfo == NULL)
	{
		GlobalUnlock(hf);
		GlobalUnlock(lp->hImage);
		return FALSE;
	}
		
	if ((pDibInfo = (LPBITMAPINFO)GlobalLock(hDibInfo)) != NULL)
	{
		pDibInfo->bmiHeader.biSize = (long)sizeof(BITMAPINFOHEADER);
		pDibInfo->bmiHeader.biWidth = (long)lp->fi.Width;
		pDibInfo->bmiHeader.biHeight = (long)lp->fi.Depth;
		pDibInfo->bmiHeader.biPlanes = 1;
		pDibInfo->bmiHeader.biBitCount = lp->nImageBits;

		for (i = 0; i < j; ++i)
		{
			pDibInfo->bmiColors[i].rgbRed = lp->fi.Palette[i * RGB_SIZE + RGB_RED];			
			pDibInfo->bmiColors[i].rgbGreen = lp->fi.Palette[i * RGB_SIZE + RGB_GREEN];			
			pDibInfo->bmiColors[i].rgbBlue = lp->fi.Palette[i * RGB_SIZE + RGB_BLUE];			
		}
	}

	if ((hbmp = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)&(pDibInfo->bmiHeader), CBM_INIT, 
		(LPSTR)p, (LPBITMAPINFO)pDibInfo, DIB_RGB_COLORS)) != NULL)
	{
		if ((hdcMem = CreateCompatibleDC(hDC)) != NULL)
		{
			if (!bTile)
			{
//				jd 27/5/98
//				if ((rc.top > 0) || (rc.left > 0))
//				{
//					x = rc.left;
//					y = rc.top;
//				}
//				else
//				{
					if ((int)lp->fi.Width > rc.right)
						x = 0;
					else
//						x = (RCWIDTH(rc) - lp->fi.Width) / 2;
						x = rc.left + (((rc.right - rc.left) - lp->fi.Width) / 2);
					if ((int)lp->fi.Depth > (rc.bottom - rc.top))
						y = rc.top;
					else
						y = rc.top + (((rc.bottom - rc.top) - lp->fi.Depth) / 2);

////////////////////////////////////////////////////////////////////	
//					jd 16/5/01 - taken out
//					if ((x != 0) || (y != 0))
//					{
//						FillRect(hDC, &rc, hbr);
//					}			
//				}
////////////////////////////////////////////////////////////////////	

			}
			hbmpOld = SelectObject(hdcMem, hbmp);
			if (hbmpOld)
			{
				if (bTile)
				{
           for (y = rc.top; y < rc.bottom; y += lp->fi.Depth)
           {
            	for (x = 0; x < rc.right; x += lp->fi.Width)
            	{
								BitBlt(hDC, x, y, lp->fi.Width, lp->fi.Depth, hdcMem, 0, 0, SRCCOPY);
							}
					 }
				}				
				else
				{
					BitBlt(hDC, x, y, lp->fi.Width, lp->fi.Depth, hdcMem, 0, 0, SRCCOPY);
////////////////////////////////////////////////////////////////////	
//				jd 16/5/01 - fill in remaining background
					ExcludeClipRect(hDC, x, y, x+lp->fi.Width, y+lp->fi.Depth);
					FillRect(hDC, &rc, hbr);
////////////////////////////////////////////////////////////////////	
				}
				SelectObject(hdcMem, hbmpOld);
			}
			DeleteDC(hdcMem);
		}
		DeleteObject(hbmp);
	}
	
	SelectObject(hDC, hbmpOld);
	SelectPalette(hDC, hpalOld, 0);
	GlobalUnlock(hDibInfo);
	GlobalFree(hDibInfo);
	GlobalUnlock(lp->hImage);
	GlobalUnlock(hf);
	return TRUE;
}

HBRUSH WINAPI BmpCreateBrush(HFILEBITMAP hf)
{
	LPFILEBITMAP lp;
	LPBITMAPINFO pDibInfo;           
	HGLOBAL hDibInfo;
	int n, j;
	LPSTR p;         
	HBRUSH hbr;
	long lSize;
	long sz1, sz2, sz3;
	LPSTR ptr1, ptr2;
	

	if (hf == NULL)
		return NULL;

	lp = (LPFILEBITMAP)GlobalLock(hf);
	if (lp == NULL)
		return NULL;

	if (lp->hImage == NULL)
		return FALSE;

	if ((p = GlobalLock(lp->hImage)) == NULL)
		return NULL;
	
	n = 1 << lp->nImageBits;
	j = __max(n,256);

	sz1 = sizeof(BITMAPINFOHEADER);
	sz2 = sizeof(RGBQUAD);
	sz3 = GlobalSize(lp->hImage);
	
	lSize = sz1 + (256 * sz2) + sz3;
//	lSize = sizeof(BITMAPINFOHEADER) + GlobalSize(lp->hImage);
	hDibInfo = GlobalAlloc(GHND, lSize);
	if (hDibInfo == NULL)
	{	
		GlobalUnlock(hf);
		GlobalUnlock(lp->hImage);
		return NULL;
	}

	if ((pDibInfo = (LPBITMAPINFO)GlobalLock(hDibInfo)) != NULL)
	{
		pDibInfo->bmiHeader.biSize = (long)sizeof(BITMAPINFOHEADER);
		pDibInfo->bmiHeader.biWidth = (long)lp->fi.Width;
		pDibInfo->bmiHeader.biHeight = (long)lp->fi.Depth;
		pDibInfo->bmiHeader.biPlanes = 1;
		pDibInfo->bmiHeader.biBitCount = lp->nImageBits;
		pDibInfo->bmiHeader.biCompression = BI_RGB;		
		pDibInfo->bmiHeader.biSizeImage = 0;		
		pDibInfo->bmiHeader.biXPelsPerMeter = 0;		
		pDibInfo->bmiHeader.biYPelsPerMeter = 0;		
		pDibInfo->bmiHeader.biClrUsed = 0;		
		pDibInfo->bmiHeader.biClrImportant = 0;		

		lstrcpyn((LPSTR)&pDibInfo->bmiColors[0], p, (int)sz3);
	
		ptr1 = (LPSTR)pDibInfo->bmiColors;
		ptr2 = p;
		for (n = 0; n < sz3; n++)
			*ptr1++ = *ptr2++;  
		
	}

	hbr = CreateDIBPatternBrush(hDibInfo, DIB_RGB_COLORS);
	if (hbr == NULL)
	{
		GlobalFree(hDibInfo);
		GlobalUnlock(hf);
		GlobalUnlock(lp->hImage);
		return NULL;
	}
	
	lp->hDibInfo = hDibInfo;
	lp->hBrush = hbr;
	GlobalUnlock(hf);
	GlobalUnlock(lp->hImage);
	return hbr;
}

void WINAPI BmpDestroyBrush(HFILEBITMAP hf)
{
	LPFILEBITMAP lp;

 	if (hf == NULL)
 		return;
	lp = (LPFILEBITMAP)GlobalLock(hf);
	if (lp == NULL)
		return; 	
	if (lp->hBrush != NULL)
	{
		DeleteObject(lp->hBrush);
		lp->hBrush = NULL;
	}
	if (lp->hDibInfo != NULL)
	{
		GlobalFree(lp->hDibInfo);
		lp->hDibInfo = NULL;
	}
	GlobalUnlock(hf);
}

HPALETTE WINAPI BmpRealizePalette(HFILEBITMAP hf, HDC hDC)
{
	LPFILEBITMAP lp;
	HPALETTE hpalOld;
	LPSTR p;         

	if (hf == NULL)
	{
		return NULL;
	}

	lp = (LPFILEBITMAP)GlobalLock(hf);
	if (lp == NULL)
	{
		return NULL;
	}
	if (lp->hImage == NULL)
	{
		return NULL;
	}
	if ((p = GlobalLock(lp->hImage)) == NULL)
		return NULL;
	
	hpalOld = SelectPalette(hDC, lp->hPalette, 0);
	RealizePalette(hDC);
	return hpalOld;
}

void WINAPI BmpDestroy(HFILEBITMAP hf)
{
	LPFILEBITMAP lp;

 	if (hf == NULL)
 		return;
	lp = (LPFILEBITMAP)GlobalLock(hf);
	if (lp == NULL)
		return; 	
 	
 	if (lp->hPalette != NULL)
 		DeleteObject(lp->hPalette);
 	if (lp->hImage != NULL)
		GlobalFree(lp->hImage);
	GlobalUnlock(hf);
	GlobalFree(hf);
}

BOOL WINAPI BmpGetSize(HFILEBITMAP hf, SIZE FAR *lpSize)
{
	LPFILEBITMAP lp;

 	if (hf == NULL)
 		return TRUE;
	lp = (LPFILEBITMAP)GlobalLock(hf);
	if (lp == NULL)
		return FALSE; 	
  lpSize->cx = lp->fi.Width;
  lpSize->cy = lp->fi.Depth;
	return TRUE;
}

#else
#include "windows.h"
#include "filebmp.h"
//stubs that do nothing under Windows CE
HANDLE WINAPI BmpCreate(LPTSTR lpszPath)
{
	return NULL;
}
BOOL WINAPI BmpPaint(HFILEBITMAP hf, HDC hDC, RECT rc, BOOL bTile, HBRUSH hbr)
{
	return FALSE;
}
HBRUSH WINAPI BmpCreateBrush(HFILEBITMAP hf)
{
	return NULL;
}
void WINAPI BmpDestroyBrush(HFILEBITMAP hf)
{
}
void WINAPI BmpDestroy(HFILEBITMAP hf)
{
}
BOOL WINAPI BmpGetSize(HFILEBITMAP hf, SIZE FAR *lpSize)
{
	return FALSE;
}
HPALETTE WINAPI BmpRealizePalette(HFILEBITMAP hf, HDC hDC)
{
	return NULL;
}
#endif //UNDER_CE